package com.kinyx.framework.utils;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;

import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.ReturnNull;
import com.kinyx.framework.annotation.assist.Tester;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.enums.impl.ErrorCode0;
import com.kinyx.framework.exception.KRuntimeException;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * 数组工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KArrayUtils {

	@ReturnNotNull
	public static <T> boolean isEmpty(@CanNull final T[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final byte[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final short[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final int[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final long[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final float[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final double[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final char[] arr) { return (arr == null) || (arr.length == 0); }
	@ReturnNotNull
	public static boolean isEmpty(@CanNull final boolean[] arr) { return (arr == null) || (arr.length == 0); }

	/**
	 * 转换为列表
	 * @param <T> 泛型
	 * @param items 数组
	 * @return 列表
	 */
	@SafeVarargs
	@ReturnNull("items == null")
	public static <T> List<T> toList(@CanNull final T... items) {
		if (items == null) { return null; }
		return Arrays.asList(items);
	}

	/**
	 * 转换为数组
	 * @param <T> 泛型
	 * @param items 数组
	 * @return 数组
	 */
	@SafeVarargs
	@ReturnNull("items == null")
	public static <T> T[] toArray(@CanNull final T... items) { return items; }

	/**
	 * 新建数组
	 * @param <T> 泛型
	 * @param clazz 类型
	 * @return 数组
	 */
	@SuppressWarnings("unchecked")
	@ReturnNotNull
	public static <T> T[] newArray(@CanNotNull final Class<T> clazz) { return (T[]) Array.newInstance(clazz, 0); }

	/**
	 * 转换为字符串
	 * @param arr 数组
	 * @param escape true：将每一个字符串元素前后都增加双引号；false：不做特殊处理；
	 * @return 字符串
	 */
	@ReturnNull("arr == null")
	public static String toString(@CanNull final String[] arr, @CanNotNull final boolean escape) {
		if (arr == null) { return null; }
		if (!escape) { return Arrays.toString(arr); }

		final int iMax = arr.length - 1;
		if (iMax == -1) { return "[]"; }

		final StringBuilder b = new StringBuilder();
		b.append('[');
		for (int i = 0;; i++) {
			final String str = arr[i];
			b.append(str == null ? null : (str instanceof String) ? "\"" + str + "\"" : str.toString());
			if (i == iMax) { return b.append(']').toString(); }
			b.append(", ");
		}
	}

	@ReturnNull("arr == null")
	public static String toString(@CanNull final Object[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final byte[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final short[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final int[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final long[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final float[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final double[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final char[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }
	@ReturnNull("arr == null")
	public static String toString(@CanNull final boolean[] arr) { if (arr == null) { return null; } return Arrays.toString(arr); }

	/**
	 * 取子数组
	 * @param arr 数组
	 * @param startIndex 开始索引值（从0开始）
	 * @param endIndex 结束索引值（不包含该索引值位置的值）
	 * @return 子数组
	 */
	@ReturnNull("arr == null")
	@Throws(at = "KArrayUtils.subArray(byte[], int, int)", value = "ErrorCode0.StartIndexLessThenMinIndex", when = "startIndex < 0")
	@Throws(at = "KArrayUtils.subArray(byte[], int, int)", value = "ErrorCode0.StartIndexMoreThenEndIndex", when = "startIndex > endIndex")
	@Throws(at = "KArrayUtils.subArray(byte[], int, int)", value = "ErrorCode0.EndIndexMoreThenMaxIndex", when = "endIndex > arr.length")
	@Tester("com.kinyx.framework.utils.KArrayUtils_Tester_subArray")
	public static byte[] subArray(@CanNull final byte[] arr, @CanNotNull final int startIndex, @CanNotNull final int endIndex) {
		if (arr == null) { return null; }
		if (arr.length == 0) { return new byte[0]; }
		if (startIndex < 0) {// 开始索引值最小只能是0
			throw new KRuntimeException(ErrorCode0.StartIndexLessThenMinIndex).param("startIndex", startIndex).param("minIndex", 0);
		}
		if (startIndex > endIndex) {// 开始索引值应小于结束索引值
			throw new KRuntimeException(ErrorCode0.StartIndexMoreThenEndIndex).param("startIndex", startIndex).param("endIndex", endIndex);
		}
		if (endIndex > arr.length) {// 结束索引值最大只能是数组长度
			throw new KRuntimeException(ErrorCode0.EndIndexMoreThenMaxIndex).param("endIndex", endIndex).param("maxIndex", arr.length);
		}
		if ((startIndex == 0) && (endIndex == arr.length)) { return arr; } // 取整个数组，直接返回。
		final byte[] sub = new byte[endIndex - startIndex];// 新建子数组
		for (int i = startIndex; i < endIndex; i++) { sub[i - startIndex] = arr[i]; } // 为子数组设置值
		return sub;// 返回结果
	}

	/**
	 * 拼接
	 * @param <T> 泛型
	 * @param arr 数组
	 * @param separator 分隔符
	 * @param converter 转换器
	 * @return 拼接结果
	 */
	@ReturnNull("arr == null")
	public static <T> String join(@CanNull final T[] arr, @CanNull(defaultValue = ",") final String separator, @CanNull(defaultValue = "toString()") final BiFunction<T, Integer, String> converter) {
		return KListUtils.join(toList(arr), separator, converter);
	}

}
